package com.tool.emulator.apple2;

import com.tool.emulator.mos6502.BUS6502;

/**
 * Console.java @author tl 2011-6-17
 */
public class Console {
	public static final boolean DELAY = true;
	public static final int TEXT_ADDR = 0x400;
	public static final int ROWS = 24;
	public static final int COLS = 40;
	public static final int CURSOR_CHAR = 96;
	public final BUS6502 bus;
	public final Apple2 apple2;
	public int TAB_SIZE = 4;
	private int current_row, current_col;

	public Console(Apple2 apple2) {
		super();
		this.apple2 = apple2;
		this.bus = apple2.BUS;
		this.cls();
	}

	public static int rowAddr(int row) {
		return TEXT_ADDR + (row % 8) * 128 + (row / 8) * 40;
	}

	private void delay(boolean scroll) {
		if (DELAY) {

			try {
				if (scroll)
					Thread.sleep(10);
				else
					Thread.sleep(1);
			} catch (Exception e) {
				System.err.println(e);
			}
		}
	}

	public void write(int row, int col, int c) {
		int addr = rowAddr(row) + col;
		bus.write(addr, c);
	}

	public synchronized void clearRow(int row) {
		int addr = rowAddr(row);
		for (int col = 0; col < COLS; col++)
			bus.write(addr++, 0xA0);
	}

	public synchronized void cls() {
		this.current_row = this.current_col = 0;
		for (int row = 1; row < ROWS; row++) clearRow(row);
	}

	private void output(int c) {
		this.write(this.current_row, this.current_col, c);
		this.current_col++;
		if (this.current_col >= COLS) {
			this.current_col = 0;
			this.current_row++;
			if (this.current_row >= ROWS) {
				this.scroll();
				this.current_row = ROWS - 1;
			}
		}
		this.writeCursor();
		delay(false);
	}

	public synchronized void print(Object x) {
		String s = String.valueOf(x);
		for (int i = 0; i < s.length(); i++) {
			int c = s.charAt(i);
			if (c == '\b') {
				if (this.current_col > 0) {
					this.write(this.current_row, this.current_col--, 0xA0);
				}
			} else if (c == '\t') {
				if (this.current_col > 0) {
					this.output(0xA0);
					while (this.current_col > 0 && this.current_col % TAB_SIZE != 0)
						this.output(0xA0);
				}
			} else if (c == '\r') {
				//ignore;
			} else if (c == '\n') {
				this.output(0xA0);
				while (this.current_col != 0) this.output(0xA0);
			} else
				this.output(c | 0x80);

		}
		this.writeCursor();
	}

	private void writeCursor() {
		write(this.current_row, this.current_col, CURSOR_CHAR);
	}

	public synchronized void println() {
		print("\n");
	}

	public synchronized void println(Object x) {
		print(x);
		println();
	}

	private void scroll() {
		int addr0 = rowAddr(0);
		for (int row = 1; row < ROWS; row++) {
			int addr1 = rowAddr(row);
			for (int col = 0; col < COLS; col++) {
				bus.write(addr0 + col, bus.read(addr1 + col));
			}
			addr0 = addr1;
		}
		for (int col = 0; col < COLS; col++)
			write(ROWS - 1, col, 0xA0);
		delay(true);
	}

}
